package com.csx.micrometer.common.util;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * Map工具类
 *
 * @author liangbeining
 * @date 2022.05.16
 */
public class MapUtil {

    private MapUtil() {
    }

    /**
     * 将一键多值类型的map转为单一键值对的的map，value取第一个
     *
     * @param multiValueMap 多ValueMap
     * @return 单一键值对的的map
     */
    public static <K, V, IV extends Iterable<V>> Map<K, V> multiValueMapToSingleValue(Map<K, IV> multiValueMap) {
        if (multiValueMap == null) {
            return null;
        }
        return multiValueMapToSingleValue(multiValueMap, new LinkedHashMap<>(multiValueMap.size()));
    }

    public static <K, V, IV extends Iterable<V>> Map<K, V> multiValueMapToSingleValue(Map<K, IV> multiValueMap, Map<K, V> resultMap) {
        return multiValueMapToSingleValue(multiValueMap, resultMap, Iterator::next);
    }


    /**
     * 将一键多值类型的map转为单一键值对的的map，value取第一个
     *
     * @param multiValueMap             多ValueMap
     * @param resultMap                 返回值接收的map
     * @param obtainSingleValueFunction 通过Iterator获取单一值得回调函数，不允许为空
     * @return 单一键值对的的map
     */
    public static <K, V, IV extends Iterable<V>> Map<K, V> multiValueMapToSingleValue(Map<K, IV> multiValueMap,
                                                                                      Map<K, V> resultMap,
                                                                                      Function<Iterator<V>, V> obtainSingleValueFunction) {
        if (multiValueMap == null) {
            return null;
        }
        for (Map.Entry<K, IV> entry : multiValueMap.entrySet()) {
            K key = entry.getKey();
            Iterable<V> value = entry.getValue();
            if (key == null || value == null) {
                continue;
            }
            Iterator<V> iterator = value.iterator();
            if (!iterator.hasNext()) {
                continue;
            }
            V next = obtainSingleValueFunction.apply(iterator);
            resultMap.put(key, next);
        }
        return resultMap;
    }
}
